import {
    parseGIF,
    parseGIFChunked,
    decompressFrames,
    ChunkedParser,
} from '../src/index.js'

// user canvas
var c = document.getElementById('c')
var ctx = c.getContext('2d')
// gif patch canvas
var tempCanvas = document.createElement('canvas')
var tempCtx = tempCanvas.getContext('2d')
// full gif canvas
var gifCanvas = document.createElement('canvas')
var gifCtx = gifCanvas.getContext('2d')

var url = document.getElementById('url')
// default gif
// url.value = '/demo/large_gif.gif'
url.value = '/demo/horses.gif'
// url.value = '/demo/dog.gif'
// url.value = '/demo/jblack.gif'
// url.value = 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1192467131,1889324742&fm=26&gp=0.jpg'

document.getElementById('loadGIF').onclick = loadGIF
document.getElementById('playpause').onclick = playpause
document.getElementById('edgedetect').onchange = () => {
    bEdgeDetect = !bEdgeDetect
}
document.getElementById('grayscale').onchange = () => {
    bGrayscale = !bGrayscale
}
document.getElementById('invert').onchange = () => {
    bInvert = !bInvert
}
document.getElementById('pixels').onchange = (e) => {
    pixelPercent = e.target.value
}

// load the default gif
loadGIF()
var gif

// load a gif with the current input url value
function loadGIFFull() {
    var oReq = new XMLHttpRequest()
    oReq.open('GET', url.value, true)
    oReq.responseType = 'arraybuffer'

    oReq.onreadystatechange = function (oEvent) {
        console.log('download... ', oEvent)
    }

    oReq.onload = function (oEvent) {
        var arrayBuffer = oReq.response // Note: not oReq.responseText
        if (arrayBuffer) {
            parseGIF(arrayBuffer, {
                    parseAfter: (schema, result, current, events) => {
                        // if (schema.image) {
                        //     events.terminated = true
                        //     oReq.abort()
                        // }
                        // console.log(Object.keys(schema), schema)
                    },
                })
                .then((v) => {
                    gif = v
                    console.log("gif", gif);
                    const frames = decompressFrames(gif, true)
                    // render the gif
                    renderGIF(frames)
                })
                .catch((e) => {
                    console.log('error in downloading gif, ', e)
                })
        }
    }

    oReq.send(null)
}

function loadGIFChunked() {
    debugger
    const loader = ChunkedParser.buildLoader({
        url: url.value,
        loaderType: 'fetch',
        chunkSize: 600,
    })
    const stream = ChunkedParser.buildStream(loader)
    try {
        parseGIFChunked(stream, ChunkedParser, {
                parseAfter: (schema, result, current, events) => {
                    if (schema.image) {
                        if (/first/.test(location.href)) {
                            events.terminated = true
                            loader.abort()
                        }
                    }
                    // console.log(Object.keys(schema), schema)
                },
            })
            .then((v) => {
                gif = v
                const frames = decompressFrames(gif, true)
                // render the gif
                renderGIF(frames)
            })
            .catch((e) => {
                console.log('error in downloading gif, ', e)
            })
    } catch (e) {
        console.log('error in downloading gif, ', e)
    }
}

function loadGIF() {
    loadGIFFull()
    // loadGIFChunked()
}

var playing = false
var bEdgeDetect = false
var bInvert = false
var bGrayscale = false
var pixelPercent = 100
var loadedFrames
var frameIndex

function playpause() {
    playing = !playing
    if (playing) {
        renderFrame()
    }
}

function renderGIF(frames) {
    loadedFrames = frames
    frameIndex = 0

    c.width = frames[0].dims.width
    c.height = frames[0].dims.height

    gifCanvas.width = c.width
    gifCanvas.height = c.height

    if (!playing) {
        playpause()
    }
}

var frameImageData

function drawPatch(frame) {
    var dims = frame.dims

    if (
        !frameImageData ||
        dims.width != frameImageData.width ||
        dims.height != frameImageData.height
    ) {
        tempCanvas.width = dims.width
        tempCanvas.height = dims.height
        frameImageData = tempCtx.createImageData(dims.width, dims.height)
    }

    // set the patch data as an override
    frameImageData.data.set(frame.patch)

    // draw the patch back over the canvas
    tempCtx.putImageData(frameImageData, 0, 0)

    gifCtx.drawImage(tempCanvas, dims.left, dims.top)
}

var edge = function (data, output) {
    var odata = output.data
    var width = gif.lsd.width
    var height = gif.lsd.height

    var conv = [-1, -1, -1, -1, 8, -1, -1, -1, -1]
    var halfside = Math.floor(3 / 2)

    for (var y = 0; y < height; y++) {
        for (var x = 0; x < width; x++) {
            var r = 0,
                g = 0,
                b = 0
            for (var cy = 0; cy < 3; cy++) {
                for (var cx = 0; cx < 3; cx++) {
                    var scy = y - halfside + cy
                    var scx = x - halfside + cx

                    if (scy >= 0 && scy < height && scx >= 0 && scx < width) {
                        var src = (scy * width + scx) * 4
                        var f = cy * 3 + cx
                        r += data[src] * conv[f]
                        g += data[src + 1] * conv[f]
                        b += data[src + 2] * conv[f]
                    }
                }
            }

            var i = (y * width + x) * 4
            odata[i] = r
            odata[i + 1] = g
            odata[i + 2] = b
            odata[i + 3] = 255
        }
    }

    return output
}

var invert = function (data) {
    for (var i = 0; i < data.length; i += 4) {
        data[i] = 255 - data[i] // red
        data[i + 1] = 255 - data[i + 1] // green
        data[i + 2] = 255 - data[i + 2] // blue
        data[i + 3] = 255
    }
}

var grayscale = function (data) {
    for (var i = 0; i < data.length; i += 4) {
        var avg = (data[i] + data[i + 1] + data[i + 2]) / 3
        data[i] = avg // red
        data[i + 1] = avg // green
        data[i + 2] = avg // blue
        data[i + 3] = 255
    }
}

function manipulate() {
    var imageData = gifCtx.getImageData(0, 0, gifCanvas.width, gifCanvas.height)
    var other = gifCtx.createImageData(gifCanvas.width, gifCanvas.height)

    if (bEdgeDetect) {
        imageData = edge(imageData.data, other)
    }

    if (bInvert) {
        invert(imageData.data)
    }

    if (bGrayscale) {
        grayscale(imageData.data)
    }

    // do pixelation
    var pixelsX = 5 + Math.floor((pixelPercent / 100) * (c.width - 5))
    var pixelsY = (pixelsX * c.height) / c.width

    if (pixelPercent != 100) {
        ctx.mozImageSmoothingEnabled = false
        ctx.webkitImageSmoothingEnabled = false
        ctx.imageSmoothingEnabled = false
    }

    ctx.putImageData(imageData, 0, 0)
    ctx.drawImage(c, 0, 0, c.width, c.height, 0, 0, pixelsX, pixelsY)
    ctx.drawImage(c, 0, 0, pixelsX, pixelsY, 0, 0, c.width, c.height)
}

function renderFrame() {
    // get the frame
    var frame = loadedFrames[frameIndex]

    var start = new Date().getTime()

    // gifCtx.clearRect(0, 0, c.width, c.height)

    // draw the patch
    drawPatch(frame)

    // perform manipulation
    manipulate()

    // update the frame index
    frameIndex++
    if (frameIndex >= loadedFrames.length) {
        frameIndex = 0
    }

    var end = new Date().getTime()
    var diff = end - start

    if (playing) {
        // delay the next gif frame
        setTimeout(function () {
            requestAnimationFrame(renderFrame)
            //renderFrame();
        }, Math.max(0, Math.floor(frame.delay - diff)))
    }
}